#region Copyright & License

//
// Author: Ian Davis <ian.f.davis@gmail.com>
// Copyright (c) 2007, Ian Davs
//
// Portions of this software were developed for NUnit.
// See NOTICE.txt for more information. 
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#endregion

using System;
using System.IO;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Ensurance.Tests
{
    [TestClass]
    public class EqualsFixture : MessageChecker
    {
        [TestMethod]
        public void Equals()
        {
            string nunitString = "Hello NUnit";
            string expected = nunitString;
            string actual = nunitString;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual );
        }

        [TestMethod]
        public void EqualsNull()
        {
            object obj1 = null;
            object obj2 = null;
            Ensure.AreEqual( obj1, obj2 );

            string str1 = null;
            string str2 = null;
            Ensure.AreEqual( str1, str2 );

            Stream strm1 = null;
            Stream strm2 = null;
            Ensure.AreEqual( strm1, strm2 );
        }

        [TestMethod]
        public void Bug575936Int32Int64Comparison()
        {
            long l64 = 0;
            int i32 = 0;
            Ensure.AreEqual( i32, l64 );
        }

        [TestMethod]
        public void IntegerLongComparison()
        {
            Ensure.AreEqual( 1, 1L );
            Ensure.AreEqual( 1L, 1 );
        }

        [TestMethod]
        public void IntegerEquals()
        {
            int val = 42;
            Ensure.AreEqual( val, 42 );
        }


        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void EqualsFail()
        {
            string junitString = "Goodbye JUnit";
            string expected = "Hello NUnit";

            expectedMessage =
                "  Expected string length 11 but was 13. Strings differ at index 0." + Environment.NewLine +
                "  Expected: \"Hello NUnit\"" + Environment.NewLine +
                "  But was:  \"Goodbye JUnit\"" + Environment.NewLine +
                "  -----------^" + Environment.NewLine;
            Ensure.AreEqual( expected, junitString );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void EqualsNaNFails()
        {
            expectedMessage =
                "  Expected: 1.234d +/- 0.0d" + Environment.NewLine +
                "  But was:  NaN" + Environment.NewLine;
            Ensure.AreEqual( 1.234, Double.NaN, 0.0 );
        }


        [TestMethod]
        [ExpectedException( typeof (EnsuranceException) )]
        public void NanEqualsFails()
        {
            expectedMessage =
                "  Expected: NaN" + Environment.NewLine +
                "  But was:  1.234d" + Environment.NewLine;
            Ensure.AreEqual( Double.NaN, 1.234, 0.0 );
        }

        [TestMethod]
        public void NanEqualsNaNSucceeds()
        {
            Ensure.AreEqual( Double.NaN, Double.NaN, 0.0 );
        }

        [TestMethod]
        public void NegInfinityEqualsInfinity()
        {
            Ensure.AreEqual( Double.NegativeInfinity, Double.NegativeInfinity, 0.0 );
        }

        [TestMethod]
        public void PosInfinityEqualsInfinity()
        {
            Ensure.AreEqual( Double.PositiveInfinity, Double.PositiveInfinity, 0.0 );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void PosInfinityNotEquals()
        {
            expectedMessage =
                "  Expected: Infinity" + Environment.NewLine +
                "  But was:  1.23d" + Environment.NewLine;
            Ensure.AreEqual( Double.PositiveInfinity, 1.23, 0.0 );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void PosInfinityNotEqualsNegInfinity()
        {
            expectedMessage =
                "  Expected: Infinity" + Environment.NewLine +
                "  But was:  -Infinity" + Environment.NewLine;
            Ensure.AreEqual( Double.PositiveInfinity, Double.NegativeInfinity, 0.0 );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void SinglePosInfinityNotEqualsNegInfinity()
        {
            expectedMessage =
                "  Expected: Infinity" + Environment.NewLine +
                "  But was:  -Infinity" + Environment.NewLine;
            Ensure.AreEqual( float.PositiveInfinity, float.NegativeInfinity, (float) 0.0 );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void EqualsThrowsException()
        {
            object o = new object();
            Ensure.Equals( o, o );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void ReferenceEqualsThrowsException()
        {
            object o = new object();
            Ensure.ReferenceEquals( o, o );
        }

        [TestMethod]
        public void Float()
        {
            float val = (float) 1.0;
            float expected = val;
            float actual = val;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual, (float) 0.0 );
        }

        [TestMethod]
        public void Byte()
        {
            byte val = 1;
            byte expected = val;
            byte actual = val;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual );
        }

        [TestMethod]
        public void String()
        {
            string s1 = "test";
            string s2 = new StringBuilder( s1 ).ToString();

            Ensure.IsTrue( s1.Equals( s2 ) );
            Ensure.AreEqual( s1, s2 );
        }

        [TestMethod]
        public void Short()
        {
            short val = 1;
            short expected = val;
            short actual = val;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual );
        }

        [TestMethod]
        public void Int()
        {
            int val = 1;
            int expected = val;
            int actual = val;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual );
        }

        [TestMethod]
        public void UInt()
        {
            uint val = 1;
            uint expected = val;
            uint actual = val;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual );
        }

        [TestMethod]
        public void Decimal()
        {
            decimal expected = 100m;
            decimal actual = 100.0m;
            int integer = 100;

            Ensure.IsTrue( expected == actual );
            Ensure.AreEqual( expected, actual );
            Ensure.IsTrue( expected == integer );
            Ensure.AreEqual( expected, integer );
            Ensure.IsTrue( actual == integer );
            Ensure.AreEqual( actual, integer );
        }


        /// <summary>
        /// Checks to see that a value comparison works with all types.
        /// Current version has problems when value is the same but the
        /// types are different...C# is not like Java, and doesn't automatically
        /// perform value type conversion to simplify this type of comparison.
        /// 
        /// Related to Bug575936Int32Int64Comparison, but covers all numeric
        /// types.
        /// </summary>
        [TestMethod]
        public void EqualsSameTypes()
        {
            byte b1 = 35;
            sbyte sb2 = 35;
            decimal d4 = 35;
            double d5 = 35;
            float f6 = 35;
            int i7 = 35;
            uint u8 = 35;
            long l9 = 35;
            short s10 = 35;
            ushort us11 = 35;

            Byte b12 = 35;
            SByte sb13 = 35;
            Decimal d14 = 35;
            Double d15 = 35;
            Single s16 = 35;
            Int32 i17 = 35;
            UInt32 ui18 = 35;
            Int64 i19 = 35;
            UInt64 ui20 = 35;
            Int16 i21 = 35;
            UInt16 i22 = 35;

            Ensure.AreEqual( 35, b1 );
            Ensure.AreEqual( 35, sb2 );
            Ensure.AreEqual( 35, d4 );
            Ensure.AreEqual( 35, d5 );
            Ensure.AreEqual( 35, f6 );
            Ensure.AreEqual( 35, i7 );
            Ensure.AreEqual( 35, u8 );
            Ensure.AreEqual( 35, l9 );
            Ensure.AreEqual( 35, s10 );
            Ensure.AreEqual( 35, us11 );

            Ensure.AreEqual( 35, b12 );
            Ensure.AreEqual( 35, sb13 );
            Ensure.AreEqual( 35, d14 );
            Ensure.AreEqual( 35, d15 );
            Ensure.AreEqual( 35, s16 );
            Ensure.AreEqual( 35, i17 );
            Ensure.AreEqual( 35, ui18 );
            Ensure.AreEqual( 35, i19 );
            Ensure.AreEqual( 35, ui20 );
            Ensure.AreEqual( 35, i21 );
            Ensure.AreEqual( 35, i22 );
        }

        [TestMethod]
        public void EnumsEqual()
        {
            MyEnum actual = MyEnum.a;
            Ensure.AreEqual( MyEnum.a, actual );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void EnumsNotEqual()
        {
            MyEnum actual = MyEnum.a;
            expectedMessage =
                "  Expected: c" + Environment.NewLine +
                "  But was:  a" + Environment.NewLine;
            Ensure.AreEqual( MyEnum.c, actual );
        }

        [TestMethod]
        public void DateTimeEqual()
        {
            DateTime dt1 = new DateTime( 2005, 6, 1, 7, 0, 0 );
            DateTime dt2 = new DateTime( 2005, 6, 1, 0, 0, 0 ) + TimeSpan.FromHours( 7.0 );
            Ensure.AreEqual( dt1, dt2 );
        }

        [TestMethod, ExpectedException( typeof (EnsuranceException) )]
        public void DateTimeNotEqual()
        {
            DateTime dt1 = new DateTime( 2005, 6, 1, 7, 0, 0 );
            DateTime dt2 = new DateTime( 2005, 6, 1, 0, 0, 0 );
            expectedMessage =
                "  Expected: 2005-06-01 07:00:00.000" + Environment.NewLine +
                "  But was:  2005-06-01 00:00:00.000" + Environment.NewLine;
            Ensure.AreEqual( dt1, dt2 );
        }

        [TestMethod]
        public void DoubleNotEqualMessageDisplaysAllDigits()
        {
            string message = "";

            try
            {
                double d1 = 36.1;
                double d2 = 36.099999999999994;
                Ensure.AreEqual( d1, d2 );
            }
            catch (EnsuranceException ex)
            {
                message = ex.Message;
            }

            if ( message == "" )
            {
                Ensure.Fail( "Should have thrown an EnsuranceException" );
            }

            int i = message.IndexOf( '3' );
            int j = message.IndexOf( 'd', i );
            string expected = message.Substring( i, j - i + 1 );
            i = message.IndexOf( '3', j );
            j = message.IndexOf( 'd', i );
            string actual = message.Substring( i, j - i + 1 );
            Ensure.AreNotEqual( expected, actual );
        }

        [TestMethod]
        public void FloatNotEqualMessageDisplaysAllDigits()
        {
            string message = "";

            try
            {
                float f1 = 36.125F;
                float f2 = 36.125004F;
                Ensure.AreEqual( f1, f2 );
            }
            catch (EnsuranceException ex)
            {
                message = ex.Message;
            }

            if ( message == "" )
            {
                Ensure.Fail( "Should have thrown an EnsuranceException" );
            }

            int i = message.IndexOf( '3' );
            int j = message.IndexOf( 'f', i );
            string expected = message.Substring( i, j - i + 1 );
            i = message.IndexOf( '3', j );
            j = message.IndexOf( 'f', i );
            string actual = message.Substring( i, j - i + 1 );
            Ensure.AreNotEqual( expected, actual );
        }

        [TestMethod]
        public void DoubleNotEqualMessageDisplaysTolerance()
        {
            string message = "";

            try
            {
                double d1 = 0.15;
                double d2 = 0.12;
                double tol = 0.005;
                Ensure.AreEqual( d1, d2, tol );
            }
            catch (EnsuranceException ex)
            {
                message = ex.Message;
            }

            if ( message == "" )
            {
                Ensure.Fail( "Should have thrown an EnsuranceException" );
            }

            EnsureBase<Ensure>.Strings.Contains( "+/- 0.005", message );
        }

        [TestMethod]
        public void FloatNotEqualMessageDisplaysTolerance()
        {
            string message = "";

            try
            {
                float f1 = 0.15F;
                float f2 = 0.12F;
                float tol = 0.001F;
                Ensure.AreEqual( f1, f2, tol );
            }
            catch (EnsuranceException ex)
            {
                message = ex.Message;
            }

            if ( message == "" )
            {
                Ensure.Fail( "Should have thrown an EnsuranceException" );
            }

            EnsureBase<Ensure>.Strings.Contains( "+/- 0.001", message );
        }

        #region Nested type: MyEnum

        private enum MyEnum
        {
            a,
            b,
            c
        }

        #endregion
    }
}